﻿using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace Ecobee.Net
{
	/// <summary>
	/// 
	/// </summary>
	public class ApiResult
	{
		/// <summary>
		/// Gets the HTTP Status Code.
		/// </summary>
		public HttpStatusCode HttpStatusCode { get; set; }

		/// <summary>
		/// Gets the HTTP Error Message.
		/// </summary>
		public string ErrorMessage { get; set; }

		/// <summary>
		/// Gets a value indicating if the call was successful or not.
		/// </summary>
		public bool Successful { get; set; }

		/// <summary>
		/// Gets the data returned from the API call.
		/// </summary>
		internal string Data { get; set; }

		/// <summary>
		/// Gets the error object in the response if the call has failed.
		/// </summary>
		public Error Error
		{
			get
			{
				Error returnValue = new Error();

				if (!this.Successful)
				{
					returnValue.LoadFrom(this.DataObject);
				}

				return returnValue;
			}
		}

		/// <summary>
		/// The API response code.
		/// </summary>
		public Status Status
		{
			get
			{
				Status returnValue = new Status();

				if (!this.Successful)
				{
					returnValue.LoadFrom(this.DataObject.status);
				}

				return returnValue;
			}
		}

		/// <summary>
		/// Gets the deserialized object from the response data.
		/// </summary>
		public dynamic DataObject
		{
			get
			{
				dynamic returnValue = null;

				try
				{
					returnValue = JsonConvert.DeserializeObject(this.Data);
				}
				catch
				{
					returnValue = null;
				}

				return returnValue;
			}
		}

		internal async Task ProcessResponse(HttpResponseMessage response)
		{
			this.Successful = response.IsSuccessStatusCode;
			this.Data = await response.Content.ReadAsStringAsync();
			this.HttpStatusCode = response.StatusCode;
			this.ErrorMessage = response.ReasonPhrase;
		}

		internal void Fail(Exception ex)
		{
			this.Successful = false;
			this.Data = string.Empty;
			this.HttpStatusCode = HttpStatusCode.InternalServerError;
			this.ErrorMessage = ex.Message;
		}

		/// <summary>
		/// If the API call failed, this will throw the error as an Exception.
		/// </summary>
		public void ThrowException()
		{
			// ***
			// *** Do nothing if the call was successful
			// ***
			if (!this.Successful)
			{
				// ***
				// *** This error will be treated as an inner exception if
				// *** there is a valid status response object, otherwise
				// *** it will be the primary exception.
				// ***
				ErrorCodeException innerException = null;
				if (!string.IsNullOrEmpty(this.Error.ErrorDescription))
				{
					innerException = ErrorCodeException.CreateErrorCodeException(this.Error);
				}

				// ***
				// *** Check if there is a status code and if it is a failure
				// ***
				if (this.Status != null && this.Status.Code != 0)
				{
					// ***
					// *** Throw the appropriate exception using the error
					// *** code exception (if it exists) as the inner exception.
					// ***
					ResponseCodeExceptionFactory factory = new ResponseCodeExceptionFactory();
					ResponseCodeException exception = factory.CreateInstance(this.Status.Code, innerException);

					throw exception;
				}
				else
				{
					// ***
					// *** Check for an error code and throw the exception if
					// *** it exists.
					// ***
					if (innerException != null)
					{
						// ***
						// *** Throw the error code exception
						// ***
						throw innerException;
					}
					else
					{
						throw new Unknown();
					}
				}
			}
		}
	}
}
